#pragma once
#include<iostream>
#include<fstream>
#include<sstream>
#include<string>
#include<vector>
#include<array>
#include<unordered_map>
#include<unordered_set>
#include<queue>
#include<algorithm>
#include<chrono>
#include<tuple>
#include<boost/unordered/unordered_flat_map.hpp>
#include<boost/unordered/unordered_flat_set.hpp>
#include<boost/container/flat_set.hpp>
#include<boost/container/flat_map.hpp>
#include<mutex>
#include<memory>
#include<thread>
#include<condition_variable>
#include<future>
#include<functional>
#include<stdexcept>

class cell;

struct string_hash
{
    std::size_t operator()(std::string const& s) const
    {
        return boost::hash_value(s);
    }
};

struct size_t_hash
{
    std::size_t operator()(std::size_t const& n) const
    {
        return n;
    }
};

void trim(std::string& cmd)
{
    if(cmd.empty()) return;
    int l=0,r=cmd.size()-1;
    while(l<=r&&(cmd[l]==' '||cmd[l]=='"')) ++l;
    while(r>=0&&(cmd[r]==' '||cmd[r]==','||cmd[r]=='"')) --r;
    if(l>r)
        cmd = "";
    else
        cmd=cmd.substr(l,r-l+1);
}

void splitString(const std::string& input, char delimiter, std::vector<std::string>& tokens)
{
    std::istringstream ss(input);
    std::string token;

    while (getline(ss, token, delimiter))
    {
        tokens.emplace_back(std::move(token));
    }

    return ;
}

std::size_t generate_string_hash (std::unordered_set<std::size_t>& unique_hash,std::unordered_map<std::string,std::size_t>& cache_hash,std::string const& s)
{
    if(cache_hash.count(s)) return cache_hash[s];
    std::size_t t = string_hash()(s);
    while(unique_hash.count(t)) ++t;
    return cache_hash[s] = t;
};

boost::unordered_flat_map<std::string,cell> tech_lib;

std::vector<std::string> sys_in;
std::vector<std::string> sys_out;

boost::unordered_flat_set<std::size_t,size_t_hash> hash_input;
boost::unordered_flat_set<std::size_t,size_t_hash> hash_output;

std::unordered_map<std::string,std::size_t> port_hash;
std::unordered_map<std::size_t,std::string> hash_port;

std::unordered_map<std::string,std::size_t> wire_hash;
std::unordered_map<std::size_t,std::string> hash_wire;

boost::unordered_flat_map<std::size_t,cell*,size_t_hash> global_ckt;
boost::unordered_flat_map<std::string,cell*> global_name_cell;

boost::unordered_flat_map<std::size_t,std::string,size_t_hash> patterns;
boost::unordered_flat_map<std::size_t,std::string,size_t_hash> vcd_outputs;

class fault;
std::vector<fault*> collapsed_fault;
